package com.lazypeople.task;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 下载线程类，与HttpDownloadTask逻辑保持一致
 */
public class DownloadThread extends Thread {
    private final URL httpUrl;
    private final File saveFile;
    private final long startPos;
    private final long endPos;
    private final AtomicLong downloadedBytes;
    private final int threadIndex;
    private final long[] downloaded;
    private final File tempFile;
    private final AtomicBoolean isPaused = new AtomicBoolean(false);
    private final AtomicBoolean isCanceled = new AtomicBoolean(false);
    private static final int BUFFER_SIZE = 8192;
    private static final int CONNECT_TIMEOUT = 15000;
    private static final int READ_TIMEOUT = 30000;

    /**
     * 构造函数 - 与HttpDownloadTask中创建线程的参数完全匹配
     */
    public DownloadThread(URL httpUrl, File saveFile, long startPos, long endPos,
            AtomicLong downloadedBytes, int threadIndex, long[] downloaded,
            File tempFile) {
        this.httpUrl = httpUrl;
        this.saveFile = saveFile;
        this.startPos = startPos;
        this.endPos = endPos;
        this.downloadedBytes = downloadedBytes;
        this.threadIndex = threadIndex;
        this.downloaded = downloaded;
        this.tempFile = tempFile;
        setName("DownloadThread-" + threadIndex);
    }

    @Override
    public void run() {
        HttpURLConnection connection = null;
        InputStream in = null;
        FileChannel fileChannel = null;

        try {
            // 计算实际需要下载的字节数
            long contentLength = endPos - startPos + 1;
            appendLog(
                    "线程" + threadIndex + "开始下载: 范围[" + startPos + "," + endPos + "], 大小:" + formatSize(contentLength)
                            + " \n");

            // 打开连接并设置范围请求
            connection = (HttpURLConnection) httpUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
            connection.setConnectTimeout(CONNECT_TIMEOUT);
            connection.setReadTimeout(READ_TIMEOUT);
            connection.setRequestProperty("User-Agent", "IdiotDownloader/1.0");
            connection.connect();

            // 检查响应状态
            int responseCode = connection.getResponseCode();
            if (responseCode < 200 || responseCode >= 300) {
                throw new IOException("服务器响应错误: " + responseCode);
            }

            // 打开输入流
            in = connection.getInputStream();

            // 打开文件通道，准备写入
            fileChannel = (FileChannel) Files.newByteChannel(saveFile.toPath(),
                    StandardOpenOption.WRITE, StandardOpenOption.CREATE);
            fileChannel.position(startPos);

            // 缓冲区和字节计数器
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            long threadDownloaded = 0;

            // 开始读取数据
            while ((bytesRead = in.read(buffer)) != -1) {
                // 检查是否需要暂停
                while (isPaused.get() && !isCanceled.get()) {
                    synchronized (this) {
                        wait(100); // 暂停时等待
                    }
                }

                // 检查是否取消
                if (isCanceled.get()) {
                    appendLog("线程" + threadIndex + "已取消\n");
                    break;
                }

                // 写入文件
                fileChannel.write(java.nio.ByteBuffer.wrap(buffer, 0, bytesRead));
                threadDownloaded += bytesRead;
                downloadedBytes.addAndGet(bytesRead);
                downloaded[threadIndex] = threadDownloaded; // 更新线程下载进度数组

                // 定期保存断点信息
                if (threadDownloaded % (BUFFER_SIZE * 10) == 0) {
                    saveProgress();
                }
            }

            // 最终保存进度
            if (!isCanceled.get()) {
                saveProgress();
                appendLog("线程" + threadIndex + "下载完成: " + formatSize(threadDownloaded) + "\n");
            }

        } catch (Exception e) {
            appendLog("线程" + threadIndex + "下载失败: " + e.getMessage() + "\n");
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (in != null)
                    in.close();
                if (fileChannel != null)
                    fileChannel.close();
                if (connection != null)
                    connection.disconnect();
            } catch (IOException e) {
                appendLog("线程" + threadIndex + "关闭资源失败: " + e.getMessage() + "\n");
            }
        }
    }

    /**
     * 保存下载进度到临时文件
     */
    private void saveProgress() {
        try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) {
            // 第一行是总大小，后面是每个线程的范围和已下载大小
            raf.seek(0);
            // 这里只更新当前线程的进度，总大小由HttpDownloadTask管理
            long pos = 1; // 跳过第一行
            for (int i = 0; i < threadIndex; i++) {
                pos += String.format("%d,%d\n", 0, downloaded[i]).getBytes().length;
            }
            raf.seek(pos);
            raf.writeBytes(String.format("%d,%d\n", endPos, downloaded[threadIndex]));
        } catch (IOException e) {
            appendLog("线程" + threadIndex + "保存进度失败: " + e.getMessage() + "\n");
        }
    }

    /**
     * 暂停下载 - 方法名与HttpDownloadTask中的调用匹配
     */
    public void pause() {
        isPaused.set(true);
    }

    /**
     * 取消下载 - 方法名与HttpDownloadTask中的调用匹配
     */
    public void cancel() {
        isCanceled.set(true);
        isPaused.set(false);
        synchronized (this) {
            notifyAll();
        }
    }

    /**
     * 添加日志到UI组件
     */
    private void appendLog(String text) {
        // Platform.runLater(() -> logArea.appendText(text));
    }

    /**
     * 格式化文件大小显示
     */
    private String formatSize(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        } else if (bytes < 1024 * 1024) {
            return String.format("%.1f KB", bytes / 1024.0);
        } else if (bytes < 1024 * 1024 * 1024) {
            return String.format("%.1f MB", bytes / (1024.0 * 1024));
        } else {
            return String.format("%.1f GB", bytes / (1024.0 * 1024 * 1024));
        }
    }
}